package com.atguigu.gmall.rabbit.service;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.rabbit.config.GmallCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 封装了MQ发送普通消息，以及延迟消息公共方法
 *
 * @author: atguigu
 * @create: 2023-08-11 11:35
 */
@Slf4j
@Component
public class RabbitService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //@Autowired
    //private AmqpTemplate amqpTemplate;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 将业务消息根据路由键发送到指定交换机
     *
     * @param exchange   交换机名称
     * @param routingKey 路由键
     * @param msg        业务消息
     */
    public void sendMsg(String exchange, String routingKey, Object msg) {
        try {
            //调用模板对象实现消息发送
            //rabbitTemplate.convertAndSend(exchange, routingKey, msg);
            //优化：在发送业务消息同时，带着“相关数据”
            //1.1 构建相关数据
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            GmallCorrelationData gmallCorrelationData = new GmallCorrelationData();
            gmallCorrelationData.setId(id);
            gmallCorrelationData.setExchange(exchange);
            gmallCorrelationData.setRoutingKey(routingKey);
            gmallCorrelationData.setMessage(msg);
            //1.2 将相关数据存入Redis
            String key = "mq:" + id;
            // 相关数据中包含Object类型 默认配置jackson2JsonredisSerizilizer转Object JSON失败 解决方式手动使用
            String gmallCorrelationDataStr = JSON.toJSONString(gmallCorrelationData);
            redisTemplate.opsForValue().set(key, gmallCorrelationDataStr, 5, TimeUnit.MINUTES);

            //2.发送业务消息+相关数据到RabbitMQ服务器端
            rabbitTemplate.convertAndSend(exchange, routingKey, msg, gmallCorrelationData);
        } catch (Exception e) {
            log.error("[rabbitMQ生产消息]发送消息异常：{}", e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 发送延迟消息+相关数据
     *
     * @param exchange
     * @param routingKey
     * @param ttl 延迟消息时间：单位s
     * @param msg
     */
    public void sendDelayMsg(String exchange, String routingKey, Object msg, int ttl) {
        try {
            //调用模板对象实现消息发送
            //rabbitTemplate.convertAndSend(exchange, routingKey, msg);
            //优化：在发送业务消息同时，带着“相关数据”
            //1.1 构建相关数据
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            GmallCorrelationData gmallCorrelationData = new GmallCorrelationData();
            gmallCorrelationData.setId(id);
            gmallCorrelationData.setExchange(exchange);
            gmallCorrelationData.setRoutingKey(routingKey);
            gmallCorrelationData.setMessage(msg);
            gmallCorrelationData.setDelay(true);
            gmallCorrelationData.setDelayTime(ttl);  //设置延迟消息时间 1小时
            //1.2 将相关数据存入Redis
            String key = "mq:" + id;
            // 相关数据中包含Object类型 默认配置jackson2JsonredisSerizilizer转Object JSON失败 解决方式手动使用
            String gmallCorrelationDataStr = JSON.toJSONString(gmallCorrelationData);
            redisTemplate.opsForValue().set(key, gmallCorrelationDataStr, 5, TimeUnit.MINUTES);

            //2.发送业务消息（设置消息过期时间）+相关数据 到RabbitMQ服务器端
            rabbitTemplate.convertAndSend(exchange, routingKey, msg, message -> {
                message.getMessageProperties().setDelay(ttl * 1000);
                return message;
            }, gmallCorrelationData);
        } catch (Exception e) {
            log.error("[rabbitMQ生产消息]发送延迟消息异常：{}", e);
            throw new RuntimeException(e);
        }
    }
}
